from collections import OrderedDict
from datetime import datetime as dt, timedelta, timezone

from time import mktime
from dateutil import rrule
from dateutil.parser import parse, ParserError
from dateutil.relativedelta import relativedelta

from core.logger import logger


def unit_convert(value, small_unit='B'):
    """
    将指定数字转换带单位存储空间
    :param small_unit: ["B", "KB", "MB", "GB", "TB", "PB"]
    :param value: 单位B（134 表示134B）
    :return: str 如： 25GB
    """

    if value is None:
        return value

    units = ["B", "KB", "MB", "GB", "TB", "PB"]
    if small_unit in units:
        index = units.index(small_unit)
        units = units[index:]
    size = 1024.0
    for i in range(len(units)):
        if (int(value) / size) < 1:
            return f"{value:.2f}{units[i]}"
        value = int(value) / size


def time_calc(time_number: int) -> str:
    """
    将指定数字转换为时间（格式：  00:00:00.000）
    :param time_number: 单位毫秒（134 表示134毫秒）
    :return: 字符串 如： 60:00:59,999
    """
    hUnit = 60 * 60 * 1000
    mUnit = 60 * 1000
    sUnit = 1000
    h = int(time_number / hUnit)
    m = int((time_number % hUnit) / mUnit)
    s = int(((time_number % hUnit) % mUnit) / sUnit)
    ms = ((time_number % hUnit) % mUnit) % sUnit
    calcResult = f'{str(h).zfill(2)}:{str(m).zfill(2)}:{str(s).zfill(2)}.{str(ms).zfill(3)}'
    return calcResult


def collection(str_or_ts, cst=True, dtype=None):
    """
    utc: Coordinated Universal Time  世界协调时间
    cst: China Standard Time UTC+8:00 中国标准时间  utc + 08:000
    系统本地时间  local_time 一般采用 utc + 08:000 = cst 中国标准时间

    :param str_or_ts: string|timetuple
    :param cst:   True or False
    :param dtype: string|datetime|struct_time|timestramp 时间
    :return: dict 所有没有表明时区时间类型
    """
    dt_str = None
    res = OrderedDict()
    if isinstance(str_or_ts, str):
        dt_str = parse(str_or_ts).strftime("%Y-%m-%d %X.%f")
    elif isinstance(str_or_ts, dt):
        dt_str = str_or_ts.strftime("%Y-%m-%d %X.%f")
    elif isinstance(str_or_ts, (int, float)):
        dt_str = dt.fromtimestamp(str_or_ts).strftime("%Y-%m-%d %X.%f")

    if dt_str:
        if isinstance(cst, bool):
            if cst:
                dt_cst_obj = parse(dt_str).replace(tzinfo=timezone(timedelta(hours=8)))
                dt_utc_obj = dt_cst_obj.astimezone(timezone(timedelta(hours=0)))
            else:
                dt_utc_obj = parse(dt_str).replace(tzinfo=timezone(timedelta(hours=0)))
                dt_cst_obj = dt_utc_obj.astimezone(timezone(timedelta(hours=8)))
            res['cst_str'] = dt_cst_obj.strftime("%Y-%m-%d %X")
            res['cst_timezone_str'] = dt_cst_obj.strftime("%Y-%m-%d %X")
            res['cst_dt'] = dt_cst_obj
            res['cst_ts'] = int(mktime(dt_cst_obj.timetuple()))
            res['cst_ts_ms'] = int(mktime(dt_cst_obj.timetuple()) * 1000.0 + dt_cst_obj.microsecond / 1000.0)

            res['utc_str'] = dt_utc_obj.strftime("%Y-%m-%d %X")
            res['utc_timezone_str'] = dt_utc_obj.strftime("%Y-%m-%d %X.%f %z")
            res['utc_dt'] = dt_utc_obj
            res['utc_ts'] = int(mktime(dt_utc_obj.timetuple()))
            # 毫秒
            res['utc_ts_ms'] = int(mktime(dt_utc_obj.timetuple()) * 1000.0 + dt_utc_obj.microsecond / 1000.0)
            # 微妙
            res['utc_ts_ns'] = int(mktime(dt_utc_obj.timetuple()) * 100000.0 + dt_utc_obj.microsecond / 100000.0)
    if dtype in dict(res).keys():
        return dict(res).get(dtype)
    else:
        return dict(res)


def time_interval_ranges(dtstart: str, dtend: str, second_interval=60):
    """
    :param dtstart:  '2023-01-17 00:00:00'
    :param dtend:    '2023-01-17 00:15:00'
    :param second_interval: 1分钟
    :return:
    """
    datetime_ranges = []
    try:
        items = list(rrule.rrule(rrule.SECONDLY, interval=second_interval, dtstart=parse(dtstart), until=parse(dtend)))
        # rrule.rrule(rrule.MINUTELY, interval=5, dtstart=parse('2023-01-17 00:00:00'), until=parse('2023-01-18 00:00:00')))
        if len(items) % 2 == 1:
            value = 0
        else:
            value = 1
        for index, item in enumerate(items, start=1):
            if (index % 2) == value:
                datetime_ranges.append(
                    {"begin_time": item.strftime("%Y-%m-%d %H:%M:%S"), "end_time": items[index].strftime("%Y-%m-%d %H:%M:%S")})
            else:
                if index < len(items):
                    datetime_ranges.append(
                        {"begin_time": item.strftime("%Y-%m-%d %H:%M:%S"), "end_time": items[index].strftime("%Y-%m-%d %H:%M:%S")})
            if index == len(items):
                datetime_ranges[-1]['end_time'] = (items[-1] - relativedelta(seconds=1)).strftime("%Y-%m-%d %H:%M:%S")
    except (TypeError, ParserError):
        logger.error(f"get impala queries response => {ParserError}")
        return datetime_ranges

    return datetime_ranges


if __name__ == '__main__':
    from pprint import pprint

    print(collection('2023-03-27T04:10:00.000Z', cst=False, dtype='cst_str'))
    # pprint(time_interval_ranges(dtstart='2023-01-17 00:00:00', dtend='2023-01-17 00:20:00'))
    pprint(unit_convert(278142912, small_unit='KB'))
    pprint(list(rrule.rrule(rrule.DAILY, interval=1, dtstart=parse("2023-04-14"), until=parse("2023-07-02"))))
